/***************************************************************************** 
** XXX nand_spl/board/infotm/imapx/boot_main.c XXX
** 
** Copyright (c) 2009~2014 ShangHai Infotm Ltd all rights reserved. 
** 
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** 
** Description: The first C function in PRELOADER.
**
** Author:
**     Warits   <warits.wang@infotm.com>
**      
** Revision History: 
** ----------------- 
** 1.1  XXX 03/17/2010 XXX	Warits
*****************************************************************************/

#include <common.h>
#include <asm/io.h>
#include "preloader.h"

void boot_set_stat(uint16_t stat)
{
	*(uint16_t *)CONFIG_SYS_PHY_BOOT_STAT = stat;
}

void boot_set_stat2(uint16_t stat)
{
	*(uint16_t *)(CONFIG_SYS_PHY_BOOT_STAT + 2) = stat;
}

/**
 * memcpy - Copy one area of memory to another
 * @dest: Where to copy to
 * @src: Where to copy from
 * @count: The size of the area.
 *
 * You should not use this function to access IO space, use memcpy_toio()
 * or memcpy_fromio() instead.
 */
void * memcpy(void * dest,const void *src,size_t count)
{
	char *tmp = (char *) dest, *s = (char *) src;

	count >>= 2;
	while (count--)
	{
		*(uint32_t *)tmp = *(uint32_t *)s;
		tmp += 4;
		s   += 4;
	}

	return dest;
}

void nor_boot(void)
{
	__attribute__((noreturn)) void (*uboot)(void)
		= (void *)(CONFIG_SYS_DISK_U_BOOT_DST + 0x40);

#ifdef CONFIG_SYS_NOR_RC
	/* set nor para */
	writel((readl(EMCPC_BASE_REG_PA + 0x94) & ~0x3f)
	   | CONFIG_SYS_NOR_RC, EMCPC_BASE_REG_PA + 0x94);
#endif

	memcpy((uchar *)(CONFIG_SYS_DISK_U_BOOT_DST + 0x40), (uint8_t *)(CONFIG_SYS_DISK_U0_OFFS + 0x10000000),
	   CONFIG_SYS_DISK_U_BOOT_SIZE);

	(*uboot)();
}

void boot_main(void)
{
	__attribute__((noreturn)) void (*uboot)(void);

	/* Keep GCC happy */
	uboot = 0;

	/* Init GPIOs */
	imapx200_init_gpio();
#if defined(CONFIG_SYS_EX_INIT_GPIO)
	imapx200_ex_init_gpio();
#endif

	/* Check reset status */
#ifndef CONFIG_HIBERNATE
	imapx200_check_reset();
#endif

	/* If this is enabled, the CPU can not be wake up by RTC */
#ifdef CONFIG_RTC_WAKE_SHUT
	if(readl(WP_ST) & 0x2)
	{
		writel(readl(WP_ST) | 0x2, WP_ST);
		writel(0xff, WP_MASK);
		writel(0x4, GPOW_CFG);
	}
#endif

	/* enable mmu & cache */
	mmu_table_init();
//	mmu_start();

	/* Init timer if a clean boot */
	timer_init();

	/* Search for denali eye */
#ifdef CONFIG_BOOT_AUTO_ADJUST
	if(readl(INFO2) == CONFIG_AU_MEM_MAGIC)
	  denali_study();
	else
	  *(uint32_t *)(0x40008000) = 0;

	writel(0, INFO2);
#endif

	mmu_start();
	/* First we try if USB is connected */
#if !defined(CONFIG_DISABLE_BOOT_OTG) && !defined(CONFIG_SYS_BOOT_NOR)
	if(!usb_otg_check())
	  goto __nand_boot__;

	/* Load u-boot.img from USB */
	if(usb_otg_load())
	  goto __nand_boot__;

	/* Check img validity */
	uboot = check_ubimg();
	if(!uboot)
	  goto __nand_boot__;

	boot_set_stat(CONFIG_BOOTSTAT_USB);
	(*uboot)();

__nand_boot__:
#endif

#ifndef CONFIG_SYS_BOOT_NOR
	nand_boot();
#else
	nor_boot();
#endif
}
